package com.us.usws.site.ws.resource;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;

import net.iwsh.core.security.digest.DigestUtils;
import net.iwsh.core.utils.converter.BeanConverter;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.us.usws.biz.LoginOutWorker;
import com.us.usws.common.EpServerConstants;
import com.us.usws.model.domain.system.User;
import com.us.usws.model.flat.epserver.DOEpTokens;
import com.us.usws.service.cud.EpTokensCUDService;
import com.us.usws.service.cud.UserCUDService;
import com.us.usws.service.ro.EpTokensROService;
import com.us.usws.service.ro.UserROService;
import com.us.usws.site.ws.entity.WSEntity;
import com.us.usws.site.ws.entity.WSEntityFactory;
import com.us.usws.site.ws.entity.user.WSUser;
import com.us.usws.support.uitls.ServiceFactory;
import com.us.usws.support.uitls.SiteWebContext;

/**
 * User webservice
 */
@Path("/my_accounts")
public class AccountResource {

	private static Log log = LogFactory.getFactory().getInstance(AccountResource.class);

	private UserROService uService = ServiceFactory.getInstance().getService(UserROService.class);
	private EpTokensROService epService = ServiceFactory.getInstance().getService(EpTokensROService.class);
	private EpTokensCUDService epCUDService = ServiceFactory.getInstance().getService(EpTokensCUDService.class);
	private UserCUDService uCUDS = ServiceFactory.getInstance().getService(UserCUDService.class);

	@PUT
	@Path("/pass_update.json")
	@Produces(MediaType.APPLICATION_JSON)
	public WSEntity updatePasswd(@Context HttpServletRequest request, @Context HttpServletResponse response,
			@FormParam("password") String password, @FormParam("password_confirmation") String passwordConfirm,
			@FormParam("old_password") String oldPasswd) {
		String errMsg = "\u786e\u8ba4\u5bc6\u7801\u4e0e\u5bc6\u7801\u4e0d\u540c";
		short errCode = (short) 103;
		short invalidOldPassErrCode = (short) 104;
		if (StringUtils.isBlank(oldPasswd) || StringUtils.isBlank(password) || StringUtils.isBlank(passwordConfirm)) {
			log.debug("{UpdatePasswd} :: Empty password/oldPassword/confirmPassword");
			return getReturnEntity(errMsg, errCode);
		}
		if (!password.equals(passwordConfirm)) {
			log.debug("{UpdatePasswd} :: Password [" + password + "] not equals to passwordConfirm [" + passwordConfirm + "].");
			return getReturnEntity(errMsg, errCode);
		}

		User u = LoginOutWorker.getUserByEpIdentitiesAny(request);
		if (u == null) {
			//not login yet
			log.debug("{UpdatePasswd} :: Cannot get login info.");
			return getReturnEntity("\u8bf7\u5148\u767b\u5f55", errCode);
		}

		String md5Salt = DigestUtils.md5Salt(oldPasswd);
		if (!md5Salt.equals(u.getPasswd())) {
			//invalid old pass
			log.debug("{UpdatePasswd} :: Invalid old password, input is [" + md5Salt + "], original is [" + u.getPasswd() + "].");
			return getReturnEntity("\u539f\u5bc6\u7801\u4e0d\u6b63\u786e", invalidOldPassErrCode);
		}

		String newPassMd5 = DigestUtils.md5Salt(password);
		uCUDS.updatePassword(newPassMd5, u.getUid());

		//success
		return getReturnEntity("\u4fee\u6539\u5bc6\u7801\u6210\u529f", (short) 200);
	}

	@POST
	@Path("/login.json")
	//@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	@Produces(MediaType.APPLICATION_JSON)
	public WSEntity login(@Context HttpServletRequest request, @Context HttpServletResponse response, @FormParam("login") String loginName,
			@FormParam("password") String passwd) {

		SiteWebContext wc = new SiteWebContext(request, null);
		String token = wc.getEpToken();

		WSEntity ret;

		//if header absent
		if (StringUtils.isBlank(token)) {
			log.debug("{EPLoginJson} :: Empty token.");
			return getFailUser(loginName, EpServerConstants.EP_CODE_LOGIN_FAIL_EMPTY_HEADER);
		}

		//empty param
		if (StringUtils.isBlank(loginName) || StringUtils.isBlank(passwd)) {
			log.debug("{EPLoginJson} :: Empty loginName/passwd.");
			return getFailUser(loginName, EpServerConstants.EP_CODE_LOGIN_FAIL_INVALID_PASSWD);
		}

		//if login failed

		User u = uService.getUserByLogin(loginName, passwd);
		if (u == null) {
			log.debug("{EPLoginJson} :: Invalid loginName=[" + loginName + "], passwd=[" + passwd + "].");
			return getFailUser(loginName, EpServerConstants.EP_CODE_LOGIN_FAIL_INVALID_PASSWD);
		}

		//if no data in ep_tokens
		DOEpTokens ept = epService.getEpTokens(token);
		if (ept == null) {
			log.debug("{EPLoginJson} :: No result from ep_tokens where token=[" + token + "].");
			return getFailUser(loginName, EpServerConstants.EP_CODE_LOGIN_FAIL_NO_RECORDS_OF_EP);
		}

		//if heartbeat timed out.
		long duration = (System.currentTimeMillis() - ept.getHeartbeatAt().getTime()) / 60000;
		long limit = EpServerConstants.EP_HEARTBEAT_IMIT;
		log.debug("{EPLoginJson} :: Get loginAt= [" + DateFormatUtils.format(ept.getLoginAt(), "yy-MM-dd HH:mm:ss") + "], heartbeat= ["
				+ DateFormatUtils.format(ept.getHeartbeatAt(), "yy-MM-dd HH:mm:ss") + "], durationi= [" + duration + "], while limit= ["
				+ limit + "].");

		if (duration > limit) {
			log.debug("{EPLoginJson} :: Heartbeat time's over, token=[" + token + "].");
			return getFailUser(loginName, EpServerConstants.EP_CODE_LOGIN_FAIL_HEARTBEAT_TIMEDOUT);
		}

		//all is ok, update userNo if need
		epCUDService.updateUserNo(u.getUid(), ept.getId());

		//return
		ret = getSuccessUser(u);
		return ret;
	}

	@PUT
	@Path("/logout.json")
	@Produces(MediaType.APPLICATION_JSON)
	public WSEntity logout(@Context HttpServletRequest request, @Context HttpServletResponse response) {

		SiteWebContext swc = new SiteWebContext(request, response);
		String token = swc.getEpToken();
		String userId = swc.getEpUserId();

		DOEpTokens ept = epService.getEpTokensByUserUidAndToken(userId, token);
		if (ept == null) {
			log.debug("{EPLogoutJson} :: Cannot find ep_tokens with both userId=[" + userId + "], token=[" + token
					+ "]. Retry with single token.");
			ept = epService.getEpTokens(token);
			if (ept == null) {
				log.debug("{EPLogoutJson} :: Cannot find ep_tokens event in single token.");
				return getLogoutFail();
			}
		}

		LoginOutWorker.epDeviceLogout(ept.getId());

		WSEntity ret = WSEntityFactory.getEmptyEntityWithRecords();
		ret.setCode((short) 0);
		ret.setMessage("\u6ce8\u9500\u5b8c\u6210");

		return ret;
	}

	@GET
	@Path("/needLogin.json")
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	@Produces(MediaType.APPLICATION_JSON)
	public WSEntity needLogin() {
		return getNeedLogin();
	}

	/**
	 * get success
	 * @param u
	 * @return
	 */
	private WSEntity getSuccessUser(User u) {
		WSEntity ret = WSEntityFactory.getEmptyEntityWithRecords();
		ret.setCode((short) 100);
		ret.setMessage("\u767b\u5f55\u6210\u529f");
		BeanConverter bc = BeanConverter.getDefaultConverter();
		WSUser wsu = bc.gen(u, WSUser.class);
		ret.setData(wsu);

		return ret;
	}

	/**
	 * fail
	 * @param loginName
	 * @return
	 */
	private WSEntity getNeedLogin() {
		WSEntity ret = WSEntityFactory.getEmptyEntityWithRecords();
		ret.setCode(EpServerConstants.EP_CODE_LOGIN_FAIL_NEED_LOGIN);
		ret.setMessage("\u8bbe\u5907\u6b63\u5728\u521d\u59cb\u5316\uff0c\u8bf7\u7a0d\u5019\u3002");
		return ret;
	}

	/**
	 * fail
	 * @param loginName
	 * @return
	 */
	private WSEntity getLogoutFail() {
		WSEntity ret = WSEntityFactory.getEmptyEntityWithRecords();
		ret.setCode(EpServerConstants.EP_CODE_LOGOUT_FAIL);
		ret.setMessage("\u65e0\u6548\u7528\u6237\u540d\u6216\u8bbe\u5907");
		return ret;
	}

	/**
	 * fail
	 * @param loginName
	 * @return
	 */
	private WSEntity getFailUser(String loginName, byte code) {
		WSEntity ret = WSEntityFactory.getEmptyEntityWithRecords();
		ret.setCode(code);
		ret.setMessage("\u767b\u5f55\u5931\u8d25");

		return ret;
	}

	/**
	 * get return entity
	 * @param msg
	 * @param code
	 * @return
	 */
	private WSEntity getReturnEntity(String msg, short code) {
		WSEntity ret = WSEntityFactory.getEmptyEntityWithRecords();
		ret.setCode(code);
		ret.setMessage(msg);
		return ret;
	}

}
